<?php
/**
 * Created by 深圳市亿游科技开发有限公司.
 * User: Administrator
 * Date: 2017/5/23 0023
 * Time: 下午 15:16
 */

class Base  
{
    public $db;
    public $sql;
    public $className;
    public $arr = [];
    public $loadedFiled = [];//自动加载的字段
    public $isDbData = false;
    public $autoHide = true;//自动删除敏感字段

    function __construct(){
        if(!$this->db)  $this->db = db();
        $this->className = $this->className();
    }
    
    public function __get($name) {
        return $this->$name;
    }

    public function delete($con=""){
        if(!$con ){
            $this->sql = "DELETE FROM ".$this->table()." WHERE `".$this->key()."`=".$this->keyVal();
            $this->query($this->sql);
        }else{
            $this->sql = "DELETE FROM ".$this->table()." WHERE `".$con;
            $this->query($this->sql);
        }
    }

    public  function save($con='')
    {
        $key = $this->key();
        $affectRows = 0;//有数据变化
         if(!$con &&  (!$key || !$this->$key)) {//无主键，无保存条件，直接插入
             if($this->$key=='') $this->$key = null;
             $this->$key =  $this->insertObject($con);
             if($this->$key) $affectRows = 1;
         }else{//update
             $affectRows =  $this->updateObject($con);
             if(IS_ADMIN_SYS && !$this->find($this->$key)){//外界增加的主键
                 if($this->$key=='') $this->$key = null;
                 $this->insertObject($con);
             }
         }
        return $affectRows;
    }

    public function updateObject($con=''){
        if(count($this->loadedFiled)<1) return false;//未修改

        $allField = $this->field();
        $this->sql = '';
        foreach($allField as $tempName=> $fieldDetail){
            if(!in_array($tempName,$this->loadedFiled)){
                continue;
            }
            $tempType  = strtoupper($fieldDetail[0]);
            $tempLen   = $fieldDetail[1];

            if($tempType == 'MEDIUMINT' or $tempType == 'INT'  or $tempType == 'SMALLINT' or $tempType == 'TINYINT'   ){ //safety check
                $this->$tempName = intval($this->$tempName);
            }else if($tempType == 'BIGINT'){//处理为vachar

            }


            if(is_array($this->$tempName)){
                $this->sql .=   ', `'.$tempName.'` ="'.addslashes(json_encode($this->$tempName)).'" ';
            }else if(is_numeric($this->$tempName) && ($this->$tempName==0 || $this->$tempName=='0' )){//0值处理
                $this->sql .= ', `'.$tempName.'` = 0  ';
            }else if(strtoupper($this->$tempName) =='NULL'){
                $this->sql .= ', `'.$tempName.'` = NULL  ';
            }else if(strtoupper($this->$tempName) =='CURRENT_TIMESTAMP'){
                $this->$tempName = date('Y-m-d H:i:s');
                $this->sql .= ', `'.$tempName.'` = "'.addslashes($this->$tempName).'" ';
            }else if($this->$tempName===NULL){//不能跳过
                $this->sql .= ', `'.$tempName.'` = NULL  ';
            }else{
                $this->sql .= ', `'.$tempName.'` = "'.addslashes($this->$tempName).'" ';
            }

            $this->arr[$tempName] = $this->$tempName;
        }
        if($this->sql) $this->sql = substr($this->sql,1);


        $primary = $this->key();
        if($this->$primary){//有主键
            $where = ' WHERE `'.$this->key().'`= "'.$this->$primary.'" ';
            if($con) $where .= ' AND '.$this->getFindSql($con);
        }else{
            if($con) $where = '  WHERE '.$this->getFindSql($con);
        }


        $this->sql = 'UPDATE '.$this->table().' SET '.$this->sql.' '.$where;
        $this->query($this->sql);
        return $this->db->affectedRows();
    }


    public function count($con)
    {
        $where = $this->getFindSql($con);
        return $this->db->getCount($this->table(),$where);
    }

    public function insertObject($con=''){
        $allField = $this->field();

        $fields = '';
        $values = '';

        foreach($allField as $tempName=> $fieldDetail){
            if($tempName == $this->key() && !IS_ADMIN_SYS)
            {
                continue;
            }
            $tempType  = strtoupper($fieldDetail[0]);
            $tempLen   = $fieldDetail[1];

            if($tempType == 'MEDIUMINT' or $tempType == 'INT'  or $tempType == 'SMALLINT' or $tempType == 'TINYINT'   ){ //safety check
                $this->$tempName = intval($this->$tempName);
            }else if($tempType == 'BIGINT'){//处理为varchar

            }


            $fields .= ', `'.$tempName.'` ';
            if(is_array($this->$tempName)){
                $values .= ', "'.addslashes(json_encode($this->$tempName)).'" ';
            }else if($this->$tempName===NULL || strtoupper($this->$tempName) =='NULL'){
                $values .= ', NULL ';
            }else if(strtoupper($this->$tempName) =='CURRENT_TIMESTAMP'){
                $this->$tempName = date('Y-m-d H:i:s');
                $values .= ', "'.$this->$tempName.'" ';
            }else{
                $values .= ', "'.addslashes($this->$tempName).'" ';
            }

            $this->arr[$tempName] = $this->$tempName;
        }
        $fields = substr($fields,1);
        $values = substr($values,1);


        $this->sql    = 'INSERT INTO '.$this->table().' ( '.$fields.' ) VALUES ( '.$values.' )';
        $this->query($this->sql);
        $key = $this->key();
        $this->$key =$this->db->getInsertId();
        $this->arr[$key] = $this->$key;
        return $this->$key;
    }

    //判断当前主键在数据库是否存在
    public function existsKeyVal($keyVal=''){
        if($keyVal==''){
            $key = $this->key();
            $keyVal = $this->$key;
        }

        $where = 'WHERE `'.$this->key().'` = "'.$keyVal.'"';
        $sql = 'SELECT COUNT(*) AS NUM FROM  '.$this->table().'  '.$where;
        $result = $this->db->getOne($sql);
        return $result['NUM'];
    }

    public function loadedFiled(){
        return $this->loadedFiled;
    }

    public  function load($data=""){
        $intType = ['TINYINT','SMALLINT','MEDIUMINT','INT','BIGINT','REAL','BIT','BOOLEAN','SERIAL'];
        $allField = $this->field();
        if(!$data) $data = myrequest::getJson();
        foreach($allField as $name=> $fieldDetail){
            if((defined('IS_ADMIN_SYS')&& IS_ADMIN_SYS) || (!in_array($name,$this->noLoadField()))){
                if(s($name,$data))  {
                    if(in_array($allField[$name][0],$intType)){
                        $this->$name = self::getVal($name,$data);
                    }else if(in_array($allField[$name][0],['DECIMAL','FLOAT'])){//数字类型均不做特殊处理，避免后面findSql调用出错
                        $this->$name = self::getVal($name,$data);
                    }else if(in_array($name,$this->jsonField())){
                        if(!is_array(self::getVal($name,$data))){



                            $tmpVal = stripslashes(self::getVal($name,$data));
                            $tmpJson = @json_decode($tmpVal);
                            if(is_array($tmpJson)){
                                $this->$name = $tmpJson;
                            }else{
                                $this->$name = [self::getVal($name,$data)];
                            }
                        }else{
                            $this->$name = self::getVal($name,$data);
                        }
                    }else{
                        $this->$name = self::getVal($name,$data);
                    }

                    if(!in_array($name,$this->loadedFiled)) {
                            $this->loadedFiled[] = $name;
                    }
                }
            }
        }
    }

    public static function getVal($fieldName,$data=""){
         if($data){
             if(is_array($data)){
                 return $data[$fieldName];
             }
            return $data->$fieldName;
        }else{
            return r($fieldName);
        }
    }

    public function loadData($data)
    {
        $allField = $this->field();
        foreach($allField as $name=>$fieldDetail){
            if(isset($data[$name])) {
                $tmp = r($name);
                $this->$name = $tmp;
            }
        }
    }

        
    public  function findOne($con=''){
        return $this->find($con);
    }
    
    public  function findAll($con='',$orderBy=''){
        return $this->all($con,$orderBy);
    }
    
    public  function query($sql){
        return $this->db->query($sql);
    }

    public function getConByLoad(){
        $findSql = "";
        $paramNames = $this->loadedFiled;
        //$numberType = ['TINYINT','SMALLINT','MEDIUMINT','INT','BIGINT','DECIMAL','FLOAT','DOUBLE','REAL','BIT','BOOLEAN','SERIAL'];
        $intType = ['TINYINT','SMALLINT','MEDIUMINT','INT','BIGINT','REAL','BIT','BOOLEAN','SERIAL'];
        $allFields = $this->field();
        for($i = 0 ; $i < count($paramNames); $i++){
            $field = $paramNames[$i];
            $val = $this->$field;
            if($val === '') continue; //全等于,用来和值为0进行区分
            if($this->key()==$field || in_array($allFields[$field][0],$intType)){//整数用等于
                $findSql .= " AND  {$this->table()}.`".$field.'` = "'.trim(addslashes($val)).'"  ';
            }else{
                $findSql .= " AND  {$this->table()}.`".$field.'` LIKE "%'.trim(addslashes($val)).'%"  ';
            }
        }

        if($findSql) {
            $findSql = substr($findSql,4);
            return $findSql;
        }else{//没有设置任何参数，找不到数据
            return "";
        }
    }

    public function getFindSql($con='',$orderBy=''){
        $findSql = '';
        if(!$con) {//根据load数据生成sql
            $findSql = $this->getConByLoad();
            if(!$findSql) {
                return false;
            }
        }else if(is_numeric($con)) {
            $con = intval($con);
            $findSql =  ' `'.$this->key().'`= "'.$con.'"';
        }else if(is_array($con)){
            if(is_array($con[0])){//多维数组

                foreach($con as $val){
                    if(!empty($findSql))
                    {
                        $findSql .=' AND ';
                    }

                    if(!isset($val[0])){
                        foreach($val as $keyT=>$valT){
                            $findSql .= ' `'.$keyT .'`="'.trim(addslashes($valT)).'"';
                        }
                    }else{
                        $findSql .= ' `'.$val[0] .'`="'.trim(addslashes($val[1])).'"';
                    }
                }
            }else{//键值对
                if(!isset($con[0])){
                    foreach($con as $keyT=>$valT){
                        if(!empty($findSql))
                        {
                            $findSql .=' AND ';
                        }
                        $findSql .= ' `'.$keyT .'`="'.trim(addslashes($valT)).'"';
                    }
                }else{//一维数组
                    if(!empty($findSql))
                    {
                        $findSql .=' AND ';
                    }
                    $findSql .= ' `'.$con[0] .'`="'.trim(addslashes($con[1])).'"';
                }
            }
        }else{
            $findSql = $con;
        }

        $orderBy = trim($orderBy);
        if($orderBy && !preg_match("/^order/i",$orderBy)){
            $orderBy = ' ORDER BY '.$orderBy;
        }else if(!$orderBy){
            $orderBy = ' ORDER BY `'.$this->key().'` DESC ';
        }

        $findSql .= ' '.$orderBy;
        return $findSql;
    }

    public  function find($con='',$orderBy=''){//找一条数据
        $findSql = $this->getFindSql($con,$orderBy);
        if(!$findSql){ return false; }//没有设定任何条件，则找不到任何数据

        $sql = 'SELECT * FROM `'.$this->table().'` WHERE '.$findSql;
        $object = $this->one($sql);
        if($object){
            return true;
        }else{
            return false;
        }
    }

    public function getOne($sql){
        return $this->one($sql);
    }
    
    public  function one($sql){
        $result = $this->db->getOne($sql);
        if(!$result){
            return false;
        }else{
            $this->arr = $result;
            $jsonFields = $this->jsonField();
            foreach($jsonFields as $tempField){
                $json = json_decode($this->arr[$tempField]);
                if(!$json) $this->arr[$tempField."_src"] = $this->arr[$tempField];
                $this->arr[$tempField] = $json;
            }

            $allField = $this->field();
            $this->isDbData = true;
            foreach($allField as $tempName=>$fieldDetail){
                $this->$tempName = $this->arr[$tempName];
            }
            $this->isDbData = false;

            return $this->arr;
        }

    }

    public function className(){
        return $this->className;
    }

    public  function all($con='',$orderBy = ''){
        if(!$con) $con = $this->getConByLoad();
        if(!$con) $con = '1=1';
        if(!$orderBy){
            $orderBy = ' ORDER BY '.$this->key().' DESC';
        }
        $findSql = $this->getFindSql($con,$orderBy);
        $this->sql = 'SELECT * FROM `'.$this->table().'` WHERE '.$findSql.' ';
        $result = $this->db->query($this->sql);

        for($i = 0; $i < count($result); $i++){
            $result[$i] = $this->tidyRow($result[$i]);
        }

        if(IS_DEBUG){
            if(!IS_LINUX || count($result)>0){
                $result[count($result)-1]['sql'] = $this->sql;
            }
        }
        return $result;
    }

    public function arr($con=''){
        if(!$con) die("arr(\$con)错误：查询条件为空\$con=".$con);
        return $this->getArrayResult($con);
    }

    //需要约定：page表示当前页码,sql不可以加limit
    public function pager($sql,$pageSize=20,$orderBy=''){
        $page = intval(r('page'));
        $page = max(1, $page);
        $page = min(20, $page);
        $uSize = intval(r('perpage'));
        $pageSize = $uSize > 0 ? $uSize : $pageSize;

        $db = db();
        $count = null;
        $result = [];

        //---计算总数-------
        $reg = "/^\s?SELECT\s+(.*?)FROM\s+(.*)/i";
        preg_match($reg,$sql,$match);
        $countSql = 'SELECT COUNT(*) AS NUM FROM '.$match[2];
        $resultCount = $db->query($countSql);
        $count = $resultCount[0]['NUM'];

        //----order by---
        if(!preg_match("/\s+ORDER\s+/i",$sql)){
            if(!$orderBy){
                $sql .= "  ORDER BY `".$this->key().'` DESC ';
            }else{
                if(preg_match("/\s+ORDER\s+/i",$orderBy)){
                    $sql .= "  $orderBy ";
                }else{
                    $sql .= " ORDER BY  $orderBy ";
                }
            }
        }


        //-----当前查询内容--------
        $start = intval($pageSize * ($page -1));
        $sql = $sql." LIMIT $start,$pageSize";
        $result['list'] = $db->query($sql);

        if($this->autoHide){
            for($i = 0; $i < count($result['list']); $i++){
                $result['list'][$i] = $this->tidyRow($result['list'][$i]);
            }
        }


        if(IS_DEBUG) $result['sql'] = $sql;
        $result['currentCount'] = count($result['list']);
        $result['totalCount'] = $count;
        $result['total'] = $count;
        $totalPage =  ceil($count / floatval($pageSize));
        $result['totalPage'] = $totalPage;
        $result['perpage'] = $pageSize;
        $result['page'] = $page;

        return $result;
    }

    public function tidy($isHide=true){
        return $this->tidyRow($this->arr,$isHide);
    }

    public function tidyRow($row,$isHide=true){
        $jsonFields = $this->jsonField();
        $hideFields = $this->hideField();

        if(!$row) return $row;

        foreach($row as $field=>$val){
            if($row[$field]===null){//处理null
                $row[$field] = '';
            }

            if($isHide && in_array($field,$hideFields) || $field=='ip'){//隐藏字段优先处理
                if(!IS_ADMIN_SYS) {//非后台系统
                    $row[$field] = hide($val);
                }
            }else if(in_array($field,$jsonFields)){//处理json
                if(!$val || $val==null){
                    $row[$field] = [];
                }else{
                    if(!is_array($val) && $val) $row[$field] = json_decode($val);
                    if(!$row[$field]){
                        $row[$field] = [];
                    }
                }
            }

        }
        return $row;
    }

    public function search($perpage=20,$con='',$orderBy=''){//@todo 重构
        $page = intval(r('page'));
        $page = max(1, $page);
        $perpage = intval(r('perpage'));
        $perpage = $perpage > 0 ? $perpage : 20;
        $limit = ($page - 1) * $perpage . ',' . $perpage;

        return $this->getArrayResult($con,$orderBy,$limit,$perpage);
    }

    //以数组形式返回，如果设置了limit参数，则按照分页模式返回
    public function getArrayResult($con='',$orderBy = '',$limit = '',$perpage=20){
        $findSql = $this->getFindSql($con,$orderBy);
        if($findSql){
            $findSql = ' WHERE '.$findSql;
        }
        $sql = 'SELECT * FROM `'.$this->table().'`  '.$findSql.' ';
        if(!empty($limit))    {
            $sql .= $orderBy;
            return $this->pager($sql,$limit);
        }else{
            $jsonFields = $this->jsonField();
            $result = $this->db->query($sql);
            for($i = 0; $i < count($result); $i++){
                $result[$i] = $this->tidyRow($result[$i]);
            }
        }
        return $result;
    }

    public  function log(){
        echo 'log';
    }

   public  function table()
    {
        die( 'function table() need to be change');
    }
    
    public  function key(){
       die( 'function key() need to be change');
    }

    /*
     * @return string 主键的值
     * */
    public  function keyVal(){
        $key = $this->key();
        return $this->$key;
    }

    public static function jsonField(){
        //("function jsonField() need to be change");
        return [];
    }

    public static function hideField(){
        return [];
    }

    public  function field()
    {
       //die("function field() need to be change");
        return [];
    }

    public static function deleteField(){
        return [];
    }

    public function hide($arr=''){
        $allHideFields = $this->hideField();
        foreach($allHideFields as $key){
            if($arr){
                $arr[$key]  = hide($arr[$key]);
            }else{
                $this->arr[$key] = hide($this->arr[$key]);
            }
        }

        $deleteFields = $this->deleteField();
        foreach($deleteFields as $key){
            if($arr){
                $arr[$key]  = '';
                unset($arr[$key]);
            }else{
                $this->arr[$key] = '';
                unset($this->arr[$key]);
            }
        }
        return $arr;
    }

    public function hideList($arr=''){
        $allHideFields = $this->hideField();
        foreach($allHideFields as $key){
            for($i = 0; $i < count($arr); $i++){
                $arr[$i][$key]  = hide($arr[$i][$key]);
            }
        }

        $deleteFields = $this->deleteField();
        foreach($deleteFields as $key){
            for($i = 0; $i < count($arr); $i++){
               unset($arr[$i][$key]);
            }
        }
        return $arr;
    }
}